#include "FontManager.h"
#include "DX11TextureManager.h"
#include "ScreenManager.h"
#include "DX11ShaderManager.h"
#include "MapFunctions.h"

#include <D3DX10math.h>

CharacterQuad::CharacterQuad()
{
	m_size = 0.05f;
	D3DXMatrixIdentity(&m_world);
	m_cb.m_outputColour = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
	m_textureResource = NULL;
	m_textureResource = TheDX11TextureManager::Instance()->UseTexture(L"../../Assets/eras_text.png");
}

CharacterQuad::~CharacterQuad()
{
}

void CharacterQuad::Initialise(D3DXVECTOR2 uv[])
{
	float aspectRatio = TheScreenManager::Instance()->GetAspectRatio();
	D3DXVECTOR2 halfSize = D3DXVECTOR2(0.0f, 0.0f);

	if (aspectRatio != 1.0f)
	{
		if (TheScreenManager::Instance()->GetWindowHeight() > TheScreenManager::Instance()->GetWindowWidth())
		{
			halfSize = D3DXVECTOR2(m_size, m_size / aspectRatio);
		}
		else
		{
			halfSize = D3DXVECTOR2(m_size / aspectRatio, m_size);
		}
	}
	else
	{
		halfSize = D3DXVECTOR2(m_size, m_size);
	}

	for (int i = 0; i != 4; i++)
	{
		m_vertData.push_back(VertexData());
	}

	m_vertData[0].m_pos = D3DXVECTOR3(-halfSize.x, -halfSize.y, 0.0f);
	m_vertData[0].m_texCoord = uv[0];
	m_vertData[1].m_pos = D3DXVECTOR3(-halfSize.x, halfSize.y, 0.0f);
	m_vertData[1].m_texCoord = uv[1];
	m_vertData[2].m_pos = D3DXVECTOR3(halfSize.x, -halfSize.y, 0.0f);
	m_vertData[2].m_texCoord = uv[2];
	m_vertData[3].m_pos = D3DXVECTOR3(halfSize.x, halfSize.y, 0.0f);
	m_vertData[3].m_texCoord = uv[3];

	std::vector<DWORD> indices;
	indices.reserve(6);
	indices.push_back(0);
	indices.push_back(1);
	indices.push_back(2);
	indices.push_back(2);
	indices.push_back(1);
	indices.push_back(3);

	D3D11_BUFFER_DESC bd;
	D3D11_SUBRESOURCE_DATA initData;

	TheScreenManager::Instance()->InitBuffers(m_pVertexBuffer, m_pIndexBuffer, bd, initData, m_vertData, indices, &m_pConstantBuffer);
}

void CharacterQuad::Translate(const D3DXVECTOR3& pos)
{
	D3DXMATRIX mat;
	D3DXMatrixTranslation(&mat, pos.x, pos.y, pos.z);
	m_transformations.push(mat);
}

void CharacterQuad::Draw()
{
	D3DXMatrixIdentity(&m_world);

	while(!m_transformations.empty())
	{
		D3DXMATRIX tempMat = m_transformations.top();
		m_world *= tempMat;
		m_transformations.pop();
	}

	//D3DXMatrixTranslation(&m, 0.0f, 0.0f, 0.0f);

	TheScreenManager::Instance()->SetBuffers(m_pVertexBuffer, m_pIndexBuffer);

	D3DXMatrixTranspose(&m_cb.m_world, &m_world);
	D3DXMatrixTranspose(&m_cb.m_view, &TheScreenManager::Instance()->GetViewMatrix());
	D3DXMatrixTranspose(&m_cb.m_projection, &TheScreenManager::Instance()->GetProjectionMatrix());
	
	ID3D11Buffer* screenCb = TheScreenManager::Instance()->GetConstantBuffer();
	
	TheScreenManager::Instance()->GetDeviceContext()->UpdateSubresource(m_pConstantBuffer, 0, NULL, &m_cb, 0, 0);

	TheScreenManager::Instance()->GetDeviceContext()->VSSetShader(
		TheDX11ShaderManager::Instance()->UseShader("FontShader").first, NULL, 0);
	TheScreenManager::Instance()->GetDeviceContext()->PSSetShader(
		TheDX11ShaderManager::Instance()->UseShader("FontShader").second, NULL, 0);

	TheScreenManager::Instance()->GetDeviceContext()->VSSetConstantBuffers(0, 1, &m_pConstantBuffer);
	
	TheScreenManager::Instance()->GetDeviceContext()->PSSetConstantBuffers(0, 1, &m_pConstantBuffer);

	// this will be used for mutliple groups in a mesh - each with a different texture
	bool notCalled = false;
	int counter = 0;

	ID3D11SamplerState* sampState = TheDX11TextureManager::Instance()->UseDefaultSamplerState();

	TheScreenManager::Instance()->GetDeviceContext()->PSSetShaderResources(0, 1, &m_textureResource);
	TheScreenManager::Instance()->GetDeviceContext()->PSSetSamplers(0, 1, &sampState);
	

	TheScreenManager::Instance()->GetDeviceContext()->DrawIndexed(6, 0, 0);
}

void CharacterQuad::SetColour(const D3DXVECTOR4& col)
{
	m_cb.m_outputColour = col;
}

void CharacterQuad::SetSize(float f)
{
	m_size = f;
}

void CharacterQuad::SetFont(const std::wstring& font)
{
	m_texturePath = font;
	m_textureResource = TheDX11TextureManager::Instance()->UseTexture(font);
}

Font::Font()
{
	m_size = 0.05f;
}

bool Font::Load(float f)
{
	// have counter that keeps track of current ascii number
	
	float cellW = 1.0f / 16.0f;
	float cellH = 1.0f / 16.0f;
	D3DXVECTOR2 curCell;

	for (int i = 0; i != 256; i++)
	{
		curCell.x = (float)(i % 16) * (float)cellW;
		curCell.y = (float)(i / 16) * (float)cellH;

		D3DXVECTOR2 uvs[4];

		uvs[0].x = curCell.x - cellH;
		uvs[0].y = curCell.y;
		uvs[1].x = curCell.x - cellW;
		uvs[1].y = curCell.y - cellH;
		uvs[2] = curCell;
		uvs[3].x = curCell.x;
		uvs[3].y = curCell.y - cellH;
		//m_characters[i] = new CharacterQuad();
		m_characters[i].SetSize(f);
		m_characters[i].Initialise(uvs);
	}
	m_size = f;
	return true;
}

void Font::Translate(int asciiChar, const D3DXVECTOR3& pos)
{
	m_characters[asciiChar].Translate(pos);
}

void Font::Draw(int asciiChar)
{
	m_characters[asciiChar].Draw();
}

void Font::SetColour(int asciiChar, const D3DXVECTOR4& col)
{
	m_characters[asciiChar].SetColour(col);
}

void Font::SetFont(int asciiChar, const std::wstring& fontFilePath)
{
	m_characters[asciiChar].SetFont(fontFilePath);
}

float Font::GetSize() const
{
	return m_size;
}

FontManager::FontManager()
{

}

FontManager::~FontManager()
{
	for (std::map<std::string, Font*>::iterator it = m_fonts.begin();it != m_fonts.end(); ++it)
	{
		delete m_fonts[it->first];
	}
	m_fonts.clear();
}

bool FontManager::LoadFont(const std::string& tag, float size)
{
	// TODO: add check to see if the map has current tag assgned

	if (m_fonts[tag])
	{
		return true;
	}
	else
	{
		m_fonts[tag] = new Font();
		return m_fonts[tag]->Load(size);
	}
}

void FontManager::Translate(const std::string& tag, int asciiChar, const D3DXVECTOR3& pos)
{
	CheckMapElement(m_fonts, tag);
	m_fonts[tag]->Translate(asciiChar, pos);
}

void FontManager::Draw(const std::string& tag, int asciiChar)
{
	CheckMapElement(m_fonts, tag);
	m_fonts[tag]->Draw(asciiChar);
}

void FontManager::SetColour(const std::string& tag, int asciichar , const D3DXVECTOR4& col)
{
	CheckMapElement(m_fonts, tag);
	m_fonts[tag]->SetColour(asciichar, col);
}

void FontManager::SetFont(const std::string& tag, int asciichar, const std::wstring& fontFilePath)
{
	CheckMapElement(m_fonts, tag);
	m_fonts[tag]->SetFont(asciichar, fontFilePath);
}

float FontManager::GetFontSize(const std::string& tag) const
{
	return m_fonts.find(tag)->second->GetSize();
}